/* eslint-disable */
const JSEncrypt = window.JSEncrypt;
const WebControl = window.WebControl;
/* eslint-enable */

export const PLUGIN_FILE_DOWNLOAD = 'http://59.48.119.142:8091/static/智慧平台 Web 视频监控插件.exe';

export const ERROR_TYPE = {
  UNINSTALL_PLUGIN: 'UNINSTALL_PLUGIN',
};

class HKVideo {
  static _appkey = '29168256'; //综合安防管理平台提供的appkey，必填
  static _secret = 'wmcoi4qqiYwtDRUL32Hn'; //综合安防管理平台提供的secret，必填
  static _ip = '123.178.187.98'; //综合安防管理平台IP地址，必填 https://123.178.187.98:4430/
  static _port = 4430; //综合安防管理平台端口，若启用HTTPS协议，默认443
  _initCount = 0; // 初始化次数
  _oWebControl = undefined;
  _options;

  /**
   *
   * @param {Object} options
   * @param {string} options.szPluginContainer - dom 容器元素 id
   * @param {number} options.width - 容器窗口宽
   * @param {number} options.height - 容器窗口高
   * @param {string} options.layout - 布局
   * @param {string} options.playMode - 类型（0-预览/1-回放）
   * @param {function(string)} [options.messageCallback] - 消息回调
   */
  constructor(options) {
    this._options = {
      width: 480,
      height: 360,
      layout: '1x1',
      ...options,
    };
  }

  /**
   * 创建播放实例
   *
   * @param {boolean} [retry=false] - 是否重新开始尝试（每次重新尝试，自动重试 3 次）
   * @returns {Promise<void>}
   */
  async initPlugin(retry = false) {
    const self = this;
    const opts = self._options;

    if (retry) {
      self._initCount = 0;
    }

    return new Promise((resolve, reject) => {
      const domContainer = document.getElementById(opts.szPluginContainer);

      if (!domContainer) {
        reject(new Error(`元素 #${opts.szPluginContainer} 不存在！`));

        return;
      }

      self._oWebControl = new WebControl({
        szPluginContainer: opts.szPluginContainer, // 指定容器id
        iServicePortStart: 15900, // 指定起止端口号，建议使用该值
        iServicePortEnd: 15909,
        szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的 clsid
        cbConnectSuccess: async function () {
          opts?.messageCallback('创建 WebControl 实例成功！');

          // WebControl实例创建成功后需要启动服务
          try {
            await self._oWebControl.JS_StartService('window', {
              dllPath: './VideoPluginConnect.dll', // 值 "./VideoPluginConnect.dll" 写死
            });

            opts?.messageCallback('启动插件服务成功！');

            self._oWebControl.JS_SetWindowControlCallback({
              // 设置消息回调
              cbIntegrationCallBack: function (oData) {
                // oData 是封装的视频 web 插件回调消息的消息体
                if (oData.responseMsg?.type === 1) {
                  const message = oData.responseMsg.msg;

                  opts?.messageCallback(message);
                }
              },
            });

            // JS_CreateWnd 创建视频播放窗口，宽高可设定
            await self._oWebControl.JS_CreateWnd(opts.szPluginContainer, opts.width, opts.height);

            // 创建播放实例成功后初始化
            await self._init();

            resolve();
          } catch (error) {
            console.info('------ 启动插件服务失败!', error);
            // reject(error);
          }
        },

        cbConnectError: function () {
          opts?.messageCallback('创建 WebControl 实例失败！');

          self._oWebControl = null;

          // eslint-disable-next-line
          WebControl.JS_WakeUp('VideoWebPlugin://'); // 程序未启动时执行error函数，采用 wake up 来启动程序

          self._initCount++;

          if (self._initCount < 3) {
            opts?.messageCallback(`插件启动失败，等待重试，第 ${self._initCount + 1} 次...`);
            setTimeout(() => {
              resolve(self.initPlugin());
            }, 3000);
          } else {
            const err = new Error('插件启动失败，请检查插件是否安装！');

            err._type = ERROR_TYPE.UNINSTALL_PLUGIN;

            reject(err);
          }
        },
        cbConnectClose: function () {
          console.info('------ 断开');
          self._oWebControl = null;
        },
      });
    });
  }

  /**
   * 初始化
   * @returns {Promise<void>}
   * @private
   */
  async _init() {
    if (!this._oWebControl) return;

    const opts = this._options;

    opts?.messageCallback('开始初始化...');

    const pubKey = await HKVideo._getPubKey(this._oWebControl);

    ////////////////////////////////// 请自行修改以下变量值	////////////////////////////////////
    const appkey = HKVideo._appkey; //综合安防管理平台提供的appkey，必填
    const secret = HKVideo._setEncrypt(HKVideo._secret, pubKey); //综合安防管理平台提供的secret，必填
    const ip = HKVideo._ip; //综合安防管理平台IP地址，必填
    const port = HKVideo._port; //综合安防管理平台端口，若启用HTTPS协议，默认443
    const playMode = opts.playMode; //初始播放模式：0-预览，1-回放
    const snapDir = 'D:\\SnapDir'; //抓图存储路径
    const videoDir = 'D:\\VideoDir'; //紧急录像或录像剪辑存储路径
    const layout = opts.layout; //playMode指定模式的布局
    const enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互，这里总是填1
    const encryptedFields = 'secret'; //加密字段，默认加密领域为secret
    const showToolbar = 1; //是否显示工具栏，0-不显示，非0-显示
    const showSmart = 1; //是否显示智能信息（如配置移动侦测后画面上的线框），0-不显示，非0-显示
    const buttonIDs = '0,16,256,257,258,259,260,512,513,515,516,768,769'; //自定义工具条按钮
    const reconnectTimes = 6; // 重连次数

    await this._oWebControl.JS_RequestInterface({
      funcName: 'init',
      argument: JSON.stringify({
        appkey, //API网关提供的appkey
        secret, //API网关提供的secret
        ip, //API网关IP地址
        playMode, //播放模式（决定显示预览还是回放界面）
        port, //端口
        snapDir, //抓图存储路径
        videoDir, //紧急录像或录像剪辑存储路径
        layout, //布局
        enableHTTPS, //是否启用HTTPS协议
        encryptedFields, //加密字段
        showToolbar, //是否显示工具栏
        showSmart, //是否显示智能信息
        buttonIDs, //自定义工具条按钮
        reconnectTimes, // 重连次数
      }),
    });

    opts?.messageCallback('初始化成功！');
    this._oWebControl.JS_Resize(opts.width, opts.height); // 初始化后resize一次，规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
  }

  /**
   * 获取公钥
   *
   * @param {OWebControl} oWebControl
   * @returns {Promise<string>}
   * @private
   */
  static async _getPubKey(oWebControl) {
    const oData = await oWebControl.JS_RequestInterface({
      funcName: 'getRSAPubKey',
      argument: JSON.stringify({
        keyLength: 1024,
      }),
    });

    if (!oData.responseMsg.data) {
      console.info('------ 公钥申请失败！');
      throw new Error('公钥申请失败！');
    }

    console.info('------ 申请公钥完成');

    return oData.responseMsg.data;
  }

  /**
   * RSA 加密
   *
   * @param {string} value
   * @param {string} pubKey
   * @returns {string}
   * @private
   */
  static _setEncrypt(value, pubKey) {
    const encrypt = new JSEncrypt();

    encrypt.setPublicKey(pubKey);

    return encrypt.encrypt(value);
  }

  async getLayout() {
    if (!this._oWebControl) return;

    const oData = await this._oWebControl.JS_RequestInterface({
      funcName: 'getLayout',
    });

    return oData?.responseMsg?.data ?? '';
  }

  async setLayout(layout) {
    if (!this._oWebControl) return;

    const oData = await this._oWebControl.JS_RequestInterface({
      funcName: 'setLayout',
      argument: JSON.stringify({
        layout,
      }),
    });

    return oData?.responseMsg?.data ?? '';
  }

  /**
   * 关闭连接，销毁播放实例
   * @returns {Promise<void>}
   */
  async destroy() {
    if (!this._oWebControl) return;

    this._oWebControl.JS_HideWnd();
    this._oWebControl.JS_DestroyWnd();
    await this._oWebControl.JS_Disconnect();

    this._oWebControl = null;
  }
  /**
   * 开始实时预览视频
   *
   * @param {string} cameraIndexCode - 监控点编号
   * @returns {Promise<void>}
   */
  async startPreview(cameraIndexCode) {
    if (!this._oWebControl || !cameraIndexCode) return;

    cameraIndexCode = cameraIndexCode.trim();

    const streamMode = 0; //主子码流标识：0-主码流，1-子码流
    const transMode = 1; //传输协议：0-UDP，1-TCP
    const gpuMode = 0; //是否启用GPU硬解，0-不启用，1-启用
    const wndId = -1; //播放窗口序号（在2x2以上布局下可指定播放窗口）

    await this._oWebControl.JS_RequestInterface({
      funcName: 'startPreview',
      argument: JSON.stringify({
        cameraIndexCode, //监控点编号
        streamMode, //主子码流标识
        transMode, //传输协议
        gpuMode, //是否开启GPU硬解
        wndId, //可指定播放窗口
      }),
    });

    console.info('------ startPreview 请求成功');
  }

  /**
   * 设置调整插件窗口大小
   */
  async setPluginSize(width, height) {
    if (!this._oWebControl) return;

    await this._oWebControl.JS_Resize(width, height);
  }

  /**
   * 开始实时预览视频(直连/非直连)
   *
   * @param {string} cameraIndexCode - 监控点编号
   * @param {0 | 1} isDirect - 是否直连
   * @returns {Promise<void>}
   */
  async startPreviewByType(cameraArrayCode, startTimer, endTimer) {
    if (!this._oWebControl) return;

    var recordLocation = 1; //录像存储位置：0-中心存储，1-设备存储
    var transMode = 1; //传输协议：0-UDP，1-TCP
    var gpuMode = 1; //是否启用GPU硬解，0-不启用，1-启用
    var wndId = -1; //播放窗口序号（在2x2以上布局下可指定播放窗口）

    let starttimestamp = new Date(startTimer).getTime();
    let endtimestamp = new Date(endTimer).getTime();

    if (cameraArrayCode.length > 1) {
      cameraArrayCode.map(async (v, index) => {
        await this._oWebControl.JS_RequestInterface({
          funcName: 'startPlayback',
          argument: JSON.stringify({
            cameraIndexCode: v, //监控点编号
            startTimeStamp: Math.floor(starttimestamp / 1000).toString(), //录像查询开始时间戳，单位：秒
            endTimeStamp: Math.floor(endtimestamp / 1000).toString(), //录像结束开始时间戳，单位：秒
            recordLocation: recordLocation, //录像存储类型：0-中心存储，1-设备存储
            transMode: transMode, //传输协议：0-UDP，1-TCP
            gpuMode: gpuMode, //是否启用GPU硬解，0-不启用，1-启用
            wndId: index + 1, //可指定播放窗口
          }),
        });
      });
    } else {
      cameraArrayCode.map(async (v) => {
        await this._oWebControl.JS_RequestInterface({
          funcName: 'startPlayback',
          argument: JSON.stringify({
            cameraIndexCode: v, //监控点编号
            startTimeStamp: Math.floor(starttimestamp / 1000).toString(), //录像查询开始时间戳，单位：秒
            endTimeStamp: Math.floor(endtimestamp / 1000).toString(), //录像结束开始时间戳，单位：秒
            recordLocation: recordLocation, //录像存储类型：0-中心存储，1-设备存储
            transMode: transMode, //传输协议：0-UDP，1-TCP
            gpuMode: gpuMode, //是否启用GPU硬解，0-不启用，1-启用
            wndId: wndId, //可指定播放窗口
          }),
        });
      });
    }

    console.info('------ startPreview 请求成功');
  }

  /**
   * 开始实时预览视频(直连/非直连)
   *
   * @param {string} cameraIndexCode - 监控点编号
   * @param {0 | 1} isDirect - 是否直连
   * @returns {Promise<void>}
   */
  async startPreviewByTypeRT(cameraIndexCode, index = -1) {
    if (!this._oWebControl) return;
    cameraIndexCode = cameraIndexCode.trim();

    const streamMode = 0; //主子码流标识：0-主码流，1-子码流
    const transMode = 1; //传输协议：0-UDP，1-TCP
    const gpuMode = 0; //是否启用GPU硬解，0-不启用，1-启用
    const wndId = index; //播放窗口序号（在2x2以上布局下可指定播放窗口）

    await this._oWebControl.JS_RequestInterface({
      funcName: 'startPreview',
      argument: JSON.stringify({
        cameraIndexCode, //监控点编号
        streamMode, //主子码流标识
        transMode, //传输协议
        gpuMode, //是否开启GPU硬解
        wndId, //可指定播放窗口
        // ezvizDirect: isDirect,
      }),
    });

    console.info('------ startPreview 请求成功');
  }

  /**
   * 开始批量实时预览视频
   *
   * @param {string[]} [cameraIndexCodes=[]] - 监控点编号列表
   * @returns {Promise<void>}
   */
  async startMultiPreviewByCameraIndexCode(cameraIndexCodes = []) {
    if (!this._oWebControl || !cameraIndexCodes.length) return;

    cameraIndexCodes = cameraIndexCodes.map((cameraIndexCode) => cameraIndexCode.trim());

    const streamMode = 0; //主子码流标识：0-主码流，1-子码流
    const transMode = 1; //传输协议：0-UDP，1-TCP
    const gpuMode = 0; //是否启用GPU硬解，0-不启用，1-启用
    const wndId = 9; //播放窗口序号（在2x2以上布局下可指定播放窗口）

    const data_ = await this._oWebControl.JS_RequestInterface({
      funcName: 'startMultiPreviewByCameraIndexCode',
      argument: JSON.stringify({
        list: cameraIndexCodes.map((cameraIndexCode) => {
          return {
            cameraIndexCode, //监控点编号
            streamMode, //主子码流标识
            transMode, //传输协议
            gpuMode, //是否开启GPU硬解
            wndId: wndId, //可指定播放窗口
          };
        }),
      }),
    });

    console.info('------ startMultiPreviewByCameraIndexCode 请求成功', data_);
  }

  /**
   * 全屏播放
   *
   * @param {string} cameraIndexCode - 监控点编号
   * @returns {Promise<void>}
   */
  async startPreviewFullScreen() {
    if (!this._oWebControl) return;

    await this._oWebControl.JS_RequestInterface({
      funcName: 'setFullScreen',
    });

    console.info('------ startPreview 全屏播放');
  }

  /**
   * 停止全部监控实时预览
   * @returns {Promise<void>}
   */
  async stopAllPreview() {
    await this._oWebControl.JS_RequestInterface({
      funcName: 'stopAllPreview',
    });
  }

  /**
   * 隐藏窗口
   * @returns {Promise<void>}
   */
  async hideWind() {
    await this._oWebControl.JS_HideWnd();
  }

  /**
   * 显示窗口
   * @returns {Promise<void>}
   */
  async showWind() {
    await this._oWebControl.JS_ShowWnd();
  }
}

export default HKVideo;
